#pragma once
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include "Log.hpp"

static const std::string SEP = "\r\n";
static const std::string kvSEP = ": ";
static const std::string wwwroot = "wwwroot";
static const std::string defaultWWW = "index.html";
static const std::string defaultSuffix = ".html";
static const std::string httpVersion = "HTTP/1.0";
static const std::string suffixSEP = ".";

class HttpRequest
{
public:
    HttpRequest()
        : _blankLine(SEP), _path(wwwroot)
    {
    }
    bool DeSerializaHelper(std::string &in)
    {
        // 读取请求行
        int pos = in.find(SEP);
        if (pos == std::string::npos)
            return false;
        _reqLine = in.substr(0, pos);
        in.erase(0, pos + SEP.size());
        // 读取请求报头
        // flag为false表示未读到空行
        bool flag = false;
        while ((pos = in.find(SEP)) != std::string::npos)
        {
            std::string tmp = in.substr(0, pos);
            in.erase(0, pos + SEP.size());

            // 如果为空，说明读到了空行
            if (tmp.empty())
            {
                flag = true;
                break;
            }
            _headers.emplace_back(tmp);
        }
        if (!flag)
            return false;
        _content = in;
        return true;
    }
    bool ParseReqLine()
    {
        std::stringstream ss(_reqLine);
        ss >> _method >> _url >> _httpVersion;
        // 如果为空，有问题
        if (_method.empty() || _url.empty() || _httpVersion.empty())
            return false;

        // 处理路径
        _path += _url;
        if (_path.back() == '/')
            _path += defaultWWW;

        // 处理后缀
        auto pos = _path.rfind(suffixSEP);
        // 没有后缀
        if (pos == std::string::npos)
            _suffix = defaultSuffix;
        else
            _suffix = _path.substr(pos);

        return true;
    }
    bool ParseHeadlers()
    {
        for (auto &str : _headers)
        {
            auto pos = str.find(kvSEP);
            // 不是完整的报头
            if (pos == std::string::npos)
                return false;

            _kvMap[str.substr(0, pos)] = str.substr(pos + kvSEP.size());
        }
        return true;
    }
    void Print()
    {
        std::cout << "\033[1;42;33m" << _reqLine << "\033[0m" << std::endl;
        for (auto &str : _headers)
            std::cout << "\033[1;47;34m" << str << "\033[0m" << std::endl;
        std::cout << _blankLine;
        std::cout << "\033[4;47;30m" << _content << "\033[0m" << std::endl;

        std::cout << "\033[1;47;46m" << "method : " << _method << "\033[0m" << std::endl;
        std::cout << "\033[1;47;46m" << "url : " << _url << "\033[0m" << std::endl;
        std::cout << "\033[1;47;46m" << "httpVersion : " << _httpVersion << "\033[0m" << std::endl;
        std::cout << "\033[1;47;46m" << "path : " << _path << "\033[0m" << std::endl;
        std::cout << "\033[1;47;46m" << "suffix : " << _suffix << "\033[0m" << std::endl;

        // std::cout << "\033[1;47;46m" << ;
        // std::cout << "\033[0m";

        // std::cout << "\033[1;47;44m";
        // for (auto& [k, v] : _kvMap)
        // {
        //     std::cout << k << "-----" << v << std::endl;
        // }
        // std::cout << "\033[0m";
    }
    bool DeSerializa(std::string &in)
    {
        // 先将请求分割
        bool res = DeSerializaHelper(in);
        if (!res)
        {
            LOG(FATAL, "DeSerializaHelper fail\n");
            return false;
        }

        // 解析请求行
        if (!ParseReqLine())
        {
            LOG(FATAL, "ParseReqLine fail\n");
            return false;
        }

        // 解析请求报头
        if (!ParseHeadlers())
        {
            LOG(FATAL, "ParseHeadlers fail\n");
            return false;
        }

        //

        return true;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Suffix()
    {
        return _suffix;
    }
    ~HttpRequest()
    {
    }

private:
    std::string _reqLine;
    std::vector<std::string> _headers;
    std::string _blankLine;
    std::string _content;

    std::string _method;
    std::string _url;
    std::string _path;   // 路径
    std::string _suffix; // 后缀
    std::string _httpVersion;
    std::unordered_map<std::string, std::string> _kvMap;
};

class HttpResponse
{
public:
    HttpResponse()
        : _blankLine(SEP), _httpVersion(httpVersion)
    {
    }
    void AddStatusLine(int code, const std::string &desc)
    {
        _code = code;
        _descript = desc;
    }
    void AddHeadler(const std::string &k, const std::string &v)
    {
        _kvMap[k] = v;
    }
    void AddContent(const std::string &text)
    {
        _content = text;
    }
    std::string Serializa()
    {
        std::string ret;
        _statusLine = _httpVersion + " " + std::to_string(_code) + " " + _descript + SEP;
        for (auto &[k, v] : _kvMap)
        {
            _headers.emplace_back(k + kvSEP + v + SEP);
        }

        ret += _statusLine;
        for (auto &str : _headers)
            ret += str;
        ret += _blankLine;
        ret += _content;
        return ret;
    }
    ~HttpResponse()
    {
    }

private:
    std::string _statusLine;
    std::vector<std::string> _headers;
    std::string _blankLine;
    std::string _content;

    std::string _httpVersion;
    int _code;
    std::string _descript;
    std::unordered_map<std::string, std::string> _kvMap;
};

class Factory
{
public:
    static std::shared_ptr<HttpRequest> CreateHttpRequest()
    {
        return std::make_shared<HttpRequest>();
    }
    static std::shared_ptr<HttpResponse> CreateHttpResponse()
    {
        return std::make_shared<HttpResponse>();
    }
};

class HttpServer
{
public:
    HttpServer()
    {
        _contentType[".html"] = "text/html";
        _contentType[".css"] = "text/css";
        _contentType[".ico"] = "image/x-icon";
        _contentType[".html"] = "text/html";
        _contentType[".jpg"] = "image/jpeg";
        _contentType[".png"] = "image/png";

        _codeDescript[100] = "Continue";
        _codeDescript[200] = "OK";
        _codeDescript[301] = "Moved Permanently";
        _codeDescript[302] = "Found";
        _codeDescript[400] = "Bad Reques";
        _codeDescript[404] = "Not Found";
    }
    // pair.string保存path下的文件的内容，pair.second表示文件是否存在
    std::string ReadFileContent(const std::string &path, int *fileSize)
    {
        std::ifstream ifs(path, std::ios::binary);
        if (!ifs.is_open())
        {
            return "";
        }
        ifs.seekg(0, ifs.end);
        *fileSize = ifs.tellg();
        // std::cout << fileSize << std::endl;
        ifs.seekg(0, ifs.beg);
        std::string message(*fileSize, '\0');
        ifs.read((char *)message.c_str(), *fileSize);

        return message;
    }
    std::string HandlerRequest(std::string request)
    {
        std::cout << "\033[1;47;30m" << request << "\033[0m";

        auto req = Factory::CreateHttpRequest();
        req->DeSerializa(request);
        // req->Print();

        auto res = Factory::CreateHttpResponse();

        // std::cout << "bool : " << ret.second << std::endl;
        //redir
        if (req->Path() == "wwwroot/redir")
        {
            std::string newurl = "https://baidu.com";
            res->AddStatusLine(302, _codeDescript[302]);
            res->AddHeadler("Location", newurl);
        }
        else
        {
            int fileSize = 0;
            LOG(INFO, "client want %s\n", req->Path().c_str());
            std::string ret = ReadFileContent(req->Path(), &fileSize);
            // 文件打开失败
            if (ret.empty())
            {
                res->AddStatusLine(404, _codeDescript[404]);
                int t = 0;
                LOG(WARNING, "404 Not Found\n");
                auto r = ReadFileContent("wwwroot/404.html", &t);
                res->AddHeadler("Content-Type", _contentType[".html"]);
                res->AddHeadler("Content-Length", std::to_string(t));
                res->AddContent(r);
                // std::cout << res->Serializa() << std::endl;
            }
            else
            {
                res->AddStatusLine(200, _codeDescript[200]);
                res->AddHeadler("Content-Type", _contentType[req->Suffix()]);
                res->AddHeadler("Content-Length", std::to_string(fileSize));
                res->AddContent(ret);
            }
        }

        // std::string ret = "HTTP/1.0 200 OK\r\n";

        // std::string message = "<html><body><h1>This is a test!</h1></body></html>";
        // ret +=  "\r\n" + message;

        // return ret;

        return res->Serializa();
    }
    ~HttpServer()
    {
    }

private:
    std::unordered_map<std::string, std::string> _contentType;
    std::unordered_map<int, std::string> _codeDescript;
};